home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / unix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  10.6 KB  |  502 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: unix.c,v 2.6 85/08/22 16:09:38 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- UNIX interface, i.e. signal and tty fiddling.
  6.  */
  7.  
  8. /* #define BADTABSTOPS /* Obsolete -- "b" doesn't set the tabs any more */
  9.     /* Defined if (soft) tabs may have been placed at strange positions. */
  10.     /* Actually this has only effect if curses(3) is used.
  11.        However this source file doesn't #include "curses.h" so we can't
  12.        check for that, and will assume curses(3) is always used.
  13.        For very slow baudrates when curses(3) is used, it may prove useful
  14.        to undefine BADTABSTOPS.  The "b" shell script must then be modified
  15.        to keep the tabs at the UNIX 8 space apart default. */
  16.  
  17. #include "b.h" /* Only for definitions like bool, string, Hidden etc. */
  18. #include "unix.h" /* What kind of UNIX is this? */
  19.  
  20. #ifdef SIGNAL
  21. #include <signal.h>
  22. #endif SIGNAL
  23.  
  24. #ifdef SGTTY_H
  25. #include <sgtty.h>
  26. #endif SGTTY_H
  27.  
  28. extern bool slowterminal; /* Set for speeds <= 600 baud */
  29. extern bool hushbaby; /* Set if no bells are to be heard */
  30. extern bool dflag; /* Debugging mode */
  31.  
  32.  
  33. #define COPYSAVEFILE ".Bed_buf"
  34.  
  35. Visible char copysavefile[200] = COPYSAVEFILE;
  36.  
  37.  
  38. #define Ctl(x) ('x'&037)
  39.  
  40. #ifndef QUITCHAR
  41. #define QUITCHAR Ctl(\\)
  42. #endif QUITCHAR
  43.  
  44. #ifndef INTRCHAR
  45. #define INTRCHAR Ctl(])
  46. #endif INTRCHAR
  47.  
  48. #define REDRAW Ctl(L) /* From "keys.h" */
  49.  
  50.  
  51. #ifdef SIGNAL
  52. /*
  53.  * Call exit code when signal arrives, then resend the signal.
  54.  */
  55.  
  56. catch(sig)
  57.     int sig;
  58. {
  59.     signal(sig, SIG_DFL);
  60. #ifndef NDEBUG
  61.     fprintf(stderr, "*** Caught signal %d \n\r", sig);
  62.     if (sig == SIGQUIT) { /* QUIT only resets terminal modes */
  63.         endterm();
  64.         endunix();
  65.     }
  66.     else
  67. #endif NDEBUG
  68.         endall();
  69. #ifdef BTOP
  70.     termchild(); /* Kill possible child, but don't wait for it */
  71. #endif BTOP
  72.     kill(getpid(), sig);
  73. }
  74. #endif SIGNAL
  75.  
  76.  
  77. #ifdef SIGTSTP /* I.e., only on BSD systems with job control. */
  78. /*
  79.  * Reset tty modes etc. when STOP signal arrives (control-Z).
  80.  * This is like interrupt but the program may continue later
  81.  * so we must not do all exit code).
  82.  *
  83.  * In order that the code works for 4.1 and 4.2 BSD Unix (V7 and sys III/V
  84.  * don't have the SIGTSTP signal at all, so there wo don't bother), we use
  85.  * neither the awkward "-ljobs" mechanism nor the nicer but (yet!) even
  86.  * less portable sigmask/sigblock system calls.  Rather, to kill ourselves
  87.  * again after the screen and tty modes have been restored, we use another
  88.  * signal, i.e., SIGSTOP (which is uncatchable).
  89.  *
  90.  * Note! Since curses' initscr() also executes signal(SIGTSTP, tstp),
  91.  * and initscr() is called after initunix(), the name of this routine
  92.  * must be tstp, overriding a routine of the same name in the curses
  93.  * library which does not do what we want.
  94.  */
  95.  
  96. tstp(sig)
  97.     int sig;
  98. {
  99.     int (*prevttousig)() = signal(SIGTTOU, SIG_IGN);
  100.         /* Ignore SIGTTOU so stty calls won't stop us again! */
  101.     char cread = REDRAW;
  102.  
  103. #ifndef NDEBUG
  104.     if (dflag)
  105.         fprintf(stderr, "*** Caught stop signal %d \n\r", sig);
  106. #endif NDEBUG
  107.     signal(sig, SIG_DFL);
  108.     endterm();
  109.     unfixttymodes();
  110.     signal(SIGTTOU, prevttousig);
  111.     kill(getpid(), SIGSTOP); /* Hard stop */
  112.  
  113.     /*
  114.      * A stop signal made us go to sleep in Tumbolia.
  115.      * When we awake, we continue at this point.
  116.      * The world may well have changed a little bit,
  117.      * so do the tty initializations anew.
  118.      */
  119.  
  120.     fixttymodes();
  121.     initterm();
  122.  
  123. #ifdef TIOCSTI
  124.     /* Simulate receipt of REDRAW initially so we come up
  125.        with a nice display. */
  126.     ioctl(0, TIOCSTI, &cread);
  127. #endif TIOCSTI
  128.     signal(SIGTSTP, tstp);
  129. }
  130. #endif SIGTSTP
  131.  
  132.  
  133. /*
  134.  * Prepare for interrupts (UNIX `signals') to be caught so
  135.  * we can reset the tty modes and perform miscellaneous other
  136.  * exit routines.
  137.  * Note -- if a signal arrives before the call to fixttymodes,
  138.  * the unfixttymodes may render the terminal useless.  The fix is
  139.  * easy, but I'm too lazy now (just read the statuses BEFORE,
  140.  * but change them only AFTER signal setting).
  141.  */
  142.  
  143. initunix()
  144. {
  145. #ifdef SIGNAL
  146.     register int i;
  147. #endif SIGNAL
  148.  
  149. #ifndef NDEBUG
  150.     if (dflag)
  151.         fprintf(stderr, "*** initunix();\n\r");
  152. #endif NDEBUG
  153.  
  154. #ifdef SIGNAL
  155.     for (i = 1; i <= NSIG; ++i) {
  156. #ifndef NDEBUG
  157.         if (i == SIGQUIT)
  158.             continue;
  159. #endif NDEBUG
  160. #ifdef SIGCONT
  161.         if (i == SIGCONT)
  162.             continue;
  163. #endif SIGCONT
  164. #ifdef SIGCHLD
  165.         if (i == SIGCHLD)
  166.             continue;
  167. #endif SIGCHLD
  168.         if (signal(i, SIG_IGN) != SIG_IGN) {
  169.             signal(i, catch);
  170. #ifndef NDEBUG
  171.             if (dflag)
  172.                 fprintf(stderr, "Catching signal %d\n", i);
  173. #endif NDEBUG
  174.         }
  175.     }
  176.     /* Stop/continue must be handled differently, see stop() above. */
  177. #ifdef SIGTSTP
  178.     if (signal(SIGTSTP, SIG_IGN) != SIG_IGN)
  179.         signal(SIGTSTP, tstp);
  180. #endif SIGTSTP
  181.  
  182. #endif SIGNAL
  183.  
  184. #ifdef SGTTY_H
  185.     fixttymodes();
  186. #endif SGTTY_H
  187.     setcopybuffer();
  188. }
  189.  
  190.  
  191. /*
  192.  * The last termination routine to be called.
  193.  * It also resets all signals to their default status.
  194.  */
  195.  
  196. endunix()
  197. {
  198. #ifdef SIGNAL
  199.     int i;
  200. #endif SIGNAL
  201.  
  202.     fflush(stdout);
  203. #ifndef NDEBUG
  204.     if (dflag)
  205.         fprintf(stderr, "*** endunix();\n\r");
  206. #endif NDEBUG
  207. #ifdef SGTTY_H
  208.     unfixttymodes();
  209. #endif SGTTY_H
  210.  
  211. #ifdef SIGNAL
  212.     for (i = 1; i <= NSIG; ++i)
  213.         signal(i, SIG_DFL);
  214. #endif SIGNAL
  215. }
  216.  
  217.  
  218. /*
  219.  * Determine the name of the file where the copy buffer is saved.
  220.  */
  221.  
  222. Hidden Procedure
  223. setcopybuffer()
  224. {
  225.     string home = getenv("HOME");
  226.  
  227.     if (home)
  228.         sprintf(copysavefile, "%.150s/%.40s", home, COPYSAVEFILE);
  229.     /* Else, retain default initialization! */
  230. }
  231.  
  232.  
  233. /*
  234.  * Return a string like the one that perror(arg) would print
  235.  * (see UNIX manual page perror(3) for details).
  236.  * Like all C library routines returning strings, the string points
  237.  * to static storage that is overwritten on each call.
  238.  * If arg is fairly long, it may get truncated.
  239.  */
  240.  
  241. string
  242. unixerror(arg)
  243.     string arg;
  244. {
  245.     static char msg[200];
  246. #ifdef PERROR
  247.     extern int sys_nerr, errno;
  248.     extern string sys_errlist[];
  249.  
  250.     if (errno > 0 && errno < sys_nerr)
  251.         sprintf(msg, "%.80s: %.80s", arg, sys_errlist[errno]);
  252.     else
  253.         sprintf(msg, "%.80s: UNIX error %d", arg, errno);
  254. #else !PERROR
  255.     sprintf(msg, "%.68s: I/O error", arg);
  256. #endif !PERROR
  257.     msg[80] = '\0';
  258.     return msg;
  259. }
  260.  
  261.  
  262. #ifdef SGTTY_H
  263. /*
  264.  * Hacks to fix certain peculiarities due to the hostile environment
  265.  * in which the editor lives.
  266.  */
  267.  
  268. Hidden struct sgttyb oldtty;
  269.  
  270. #ifdef TIOCSETC
  271. Hidden struct tchars oldtchars;
  272. #endif
  273.  
  274. #ifdef TIOCSLTC
  275. Hidden struct ltchars oldltchars;
  276. #endif
  277.  
  278. Hidden Procedure
  279. fixttymodes()
  280. {
  281.     gtty(2, &oldtty);
  282.     if (oldtty.sg_ospeed <= B600)
  283.         slowterminal = Yes;
  284. #ifdef BADTABSTOPS
  285.     /*
  286.      * Turn on XTABS mode, to be able to live when terminal tabs are
  287.      * set at 4 rather than 8 columns (the B interpreter used to set
  288.      * this).
  289.      */
  290.     if (!(oldtty.sg_flags & XTABS)) {
  291.         struct sgttyb newtty;
  292.         gtty(2, &newtty);
  293.         newtty.sg_flags |= XTABS;
  294.         ioctl(0, TIOCSETN, &newtty);
  295.     }
  296. #endif BADTABSTOPS
  297.  
  298. #ifdef TIOCSETC /* I.e., not at pre-version 7 UNIX systems */
  299.     /*
  300.      * Set the quit character to ^\ and the interrupt at DEL.
  301.      * The start/stop characters are kept only if they are ^S/^Q.
  302.      */
  303.     {
  304.         struct tchars newtchars;
  305.         ioctl(0, TIOCGETC, &oldtchars);
  306.         ioctl(0, TIOCGETC, &newtchars);
  307.         if ((newtchars.t_intrc & 0377) != 0377
  308.             && newtchars.t_intrc != 0177/*DEL*/)
  309.             newtchars.t_intrc = INTRCHAR;
  310.         if ((newtchars.t_quitc & 0377) != 0377)
  311.             newtchars.t_quitc = QUITCHAR;
  312.         if (newtchars.t_startc != Ctl(Q))
  313.             newtchars.t_startc = -1;
  314.         if (newtchars.t_stopc != Ctl(S))
  315.             newtchars.t_stopc = -1;
  316.         ioctl(0, TIOCSETC, &newtchars);
  317.     }
  318. #endif TIOCSETC
  319.  
  320. #ifdef TIOCSLTC /* I.e., at 4.xBSD systems */
  321.     /*
  322.      * Turn off all local control characters except keep stop (^Z) and delayed
  323.      * stop (^Y) when these are the originals.
  324.      */
  325.     {
  326.         static struct ltchars newltchars = {-1, -1, -1, -1, -1, -1};
  327.  
  328.         ioctl(0, TIOCGLTC, &oldltchars);
  329.         if (oldltchars.t_suspc == Ctl(Z))
  330.             newltchars.t_dsuspc = Ctl(Z);
  331.         ioctl(0, TIOCSLTC, &newltchars);
  332.     }
  333. #endif
  334. }
  335.  
  336.  
  337. /*
  338.  * Undo the effects of fixttymodes(), see comments there.
  339.  */
  340.  
  341. Hidden Procedure
  342. unfixttymodes()
  343. {
  344.     if (!oldtty.sg_ospeed)
  345.         return; /* Not yet initialized! */
  346. #ifdef BADTABSTOPS
  347.     ioctl(0, TIOCSETN, &oldtty);
  348. #endif
  349. #ifdef TIOCSETC
  350.     ioctl(0, TIOCSETC, &oldtchars);
  351. #endif
  352. #ifdef TIOCSLTC
  353.     ioctl(0, TIOCSLTC, &oldltchars);
  354. #endif
  355. }
  356. #endif SGTTY_H
  357.  
  358.  
  359. /*
  360.  * Return Yes if more input immediately available
  361.  */
  362.  
  363. #ifdef IBMPC
  364.  
  365. Visible bool
  366. moreinput()
  367. {
  368.     return kbhit();
  369. }
  370.  
  371. #else !IBMPC
  372.  
  373. /*
  374.  * ***** UNIX DEPENDENCE *****
  375.  * Assumes the standard UNIX definition of FILE: assumes there is
  376.  * buffered input if stdin->_cnt > 0, so uses the `_cnt' field.
  377.  *
  378.  * ***** 4.2 BSD DEPENDENCE *****
  379.  * If the symbol SIGNAL is defined, uses the select() system call to determine
  380.  * whether more input is available; see select(2) in 4.2 BSD manual.
  381.  *
  382.  * ***** 4.1 BSD DEPENDENCE *****
  383.  * If the symbol FIONREAD is defined, uses the correponding ioctl call to
  384.  * determine whether more input is available; see tty(4) in 4.1 BSD manual.
  385.  */
  386.  
  387. #ifdef SELECT
  388. #include <sys/time.h>
  389. #endif SELECT
  390.  
  391. Visible bool
  392. moreinput()
  393. {
  394.     if (stdin->_cnt > 0)
  395.         return Yes;
  396. #ifdef SELECT
  397.     {
  398.         int readfds;
  399.         int nfds;
  400.         static struct timeval timeout = {0, 0};
  401.  
  402.         readfds = 1<<fileno(stdin);
  403.         nfds = 1+fileno(stdin);
  404.         nfds = select(nfds, &readfds, (int*)0, (int*)0, &timeout);
  405.         if (nfds > 0) {
  406.             if (dflag)
  407.                 fputc('\07', stderr);
  408.             return Yes;
  409.         }
  410.     }
  411. #else SELECT
  412. #ifdef FIONREAD
  413.     {
  414.         long n = 0;
  415.  
  416.         if (ioctl(0, FIONREAD, &n) != -1 && n > 0)
  417.             return Yes;
  418.     }
  419. #endif FIONREAD
  420. #endif SELECT
  421.     return No;
  422. }
  423. #endif !IBMPC
  424.  
  425.  
  426. #ifdef SETENV
  427. /*
  428.  * Routine to add or change an environment variable.
  429.  * (No longer used.)
  430.  */
  431.  
  432. extern string *environ;
  433.  
  434. setenv(entry)
  435.     string entry;
  436. {
  437.     string equals = index(entry, '=');
  438.     int len;
  439.     string *ep;
  440.     static string *myenviron;
  441.  
  442.     if (!equals)
  443.         syserr("setenv: no = sign");
  444.     len = equals - entry;
  445.     for (ep = environ; *ep && !Strnequ(*ep, entry, len+1); ++ep)
  446.         ;
  447.     if (*ep) {
  448.         *ep = entry;
  449.         return;
  450.     }
  451.     len = ep - environ + 2;
  452.     if (myenviron) {
  453.         myenviron = (string*)
  454.             realloc((string)myenviron, (unsigned)(len * sizeof(string)));
  455.         if (!myenviron)
  456.             syserr("setenv: realloc");
  457.     }
  458.     else {
  459.         myenviron = (string*) malloc((unsigned)(len * sizeof(string)));
  460.         if (!myenviron)
  461.             syserr("setenv: malloc");
  462.         for (ep = environ; *ep; ++ep)
  463.             myenviron[ep-environ] = *ep;
  464.     }
  465.     myenviron[len-1] = (string)NULL;
  466.     myenviron[len-2] = entry;
  467.     environ = myenviron;
  468. }
  469. #endif SETENV
  470.  
  471.  
  472. #ifdef PWB
  473. /*
  474.  * Substitute getenv routine - there is no environment on PWB systems,
  475.  * but as a substitute (not te be encouraged!) we allow a file with the
  476.  * name of the environment variable to contain the desired value;
  477.  * e.g. the file "TERM" may contain a line saying hp2621 or hp etc.
  478.  */
  479.  
  480. Visible string
  481. getenv(name)
  482.     string name;
  483. {
  484.     static char buffer[100];
  485.     FILE *fp;
  486.     string cp;
  487.  
  488.     fp = fopen(name, "r");
  489.     if (!fp)
  490.         return NULL;
  491.     if (!fgets(buffer, sizeof buffer, fp))
  492.         buffer[0] = '\0';
  493.     else {
  494.         cp = index(buffer, '\n');
  495.         if (cp)
  496.             *cp = '\0';
  497.     }
  498.     fclose(fp);
  499.     return buffer;
  500.  }
  501. #endif PWB
  502.